package com.sanhuo;

import com.sanhuo.triild.annotation.MapperWire;
import com.sanhuo.triild.exception.MapperException;
import com.sanhuo.triild.utils.AnnotationUtil;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;

@Component
public class MapperPostProcessor implements BeanPostProcessor {

    private static final String NOTFOUND = "this Field Cannot find proxy mapper";

    /**
     * 为带有MapperWire的字段自动注入代理类
     *
     * @param bean
     * @param beanName
     * @return
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        Field[] fields = bean.getClass().getDeclaredFields();
        if (bean.getClass().getAnnotation(Transactional.class) != null) {
            Object target = getTarget(bean);
            if (target != bean) {
                postProcessAfterInitialization(target, target.getClass().getSimpleName());
            }
        }
        for (Field field : fields) {
            // 当字段被 @Mapper 注解时，为此字段自动注入服务代理类
            if (field.getAnnotation(MapperWire.class) != null) {
                field.setAccessible(true);
//                System.out.println(field.getName());
                // 根据服务类型生成服务的动态代理
                Class<?> mapperClass = field.getType();
                if (AnnotationUtil.isMapper(mapperClass)) {
                    Object mapperProxy = MapperProxy.ProxyFactory(mapperClass);
                    // 将该字段值设置为生成的代理类
                    try {
                        field.set(bean, mapperProxy);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                } else {
                    try {
                        throw new MapperException(NOTFOUND + " : " + field.getName());
                    } catch (MapperException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return bean;
    }

    public static Object getTarget(Object beanInstance) {
        if (!AopUtils.isAopProxy(beanInstance)) {
            return beanInstance;
        } else if (AopUtils.isCglibProxy(beanInstance)) {
            try {
                Field h = beanInstance.getClass().getDeclaredField("CGLIB$CALLBACK_0");
                h.setAccessible(true);
                Object dynamicAdvisedInterceptor = h.get(beanInstance);

                Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
                advised.setAccessible(true);

                Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
                return target;
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return null;

    }
}